﻿using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;
using static Simulation.Framework.HttpManager;

namespace Simulation.Framework
{
    public class HttpManager : ManagerBehavior
    {
        public static int timeOut = 60;          // 超时
        public static int retryCount = 3;       // 重试次数
        public int downloadCount { get { return downloadQueue.Count; } }
        private List<DownloadContent> downloadQueue = new List<DownloadContent>();

        #region override

        public override void Init()
        {
            downloadQueue = new List<DownloadContent>();
        }

        public override void Clear()
        {
            StopDownloadAll();
            downloadQueue?.Clear();
            downloadQueue = null;
        }

        public override void Restar() { }

        #endregion

        #region get

        public void Get(string url, UnityAction<string, string> response)
        {
            StartCoroutine(GetIE(url, response));
        }

        private IEnumerator GetIE(string url, UnityAction<string, string> response)
        {
            using (UnityWebRequest unityWebRequest = UnityWebRequest.Get(url))
            {
                unityWebRequest.timeout = timeOut;
                yield return unityWebRequest.SendWebRequest();
                if (unityWebRequest.isNetworkError || unityWebRequest.isHttpError)
                {
                    Log.Info("错误访问：" + url + ">>" + unityWebRequest.error);
                    response?.Invoke(url, unityWebRequest.error);
                    yield break;
                }
                Log.Info("成功访问：" + url + ">>" + unityWebRequest.downloadHandler.text);
                response?.Invoke(url, unityWebRequest.downloadHandler.text);
            }
        }

        #endregion

        #region post

        public void Post(string url, Dictionary<string, string> formFields, UnityAction<string, string> response)
        {
            StartCoroutine(PostIE(url, formFields, response));
        }

        private IEnumerator PostIE(string url, Dictionary<string, string> formFields, UnityAction<string, string> response)
        {
            using (UnityWebRequest unityWebRequest = UnityWebRequest.Post(url, formFields))
            {
                unityWebRequest.timeout = timeOut;
                yield return unityWebRequest.SendWebRequest();
                if (unityWebRequest.isNetworkError || unityWebRequest.isHttpError)
                {
                    Log.Info("错误访问：" + url + ">>" + unityWebRequest.error);
                    response?.Invoke(url, unityWebRequest.error);
                    yield break;
                }
                Log.Info("成功访问：" + url + ">>" + unityWebRequest.downloadHandler.text);
                response?.Invoke(url, unityWebRequest.downloadHandler.text);
            }
        }

        #endregion

        #region download

        public void StopDownload(string url)
        {
            if (downloadQueue == null) return;
            DownloadContent content = downloadQueue.Find(v => v.url == url);
            StopDownload(content);
        }

        public void StopDownload(DownloadContent content)
        {
            if (content != null)
            {
                content.Abort();
                StopCoroutine(content.ie);
                downloadQueue.Remove(content);
            }
        }

        public void StopDownloadAll()
        {
            if (downloadQueue == null) return;
            for (int i = downloadQueue.Count - 1; i >= 0; i--)
            {
                downloadQueue[i].Abort();
                StopCoroutine(downloadQueue[i].ie);
                downloadQueue[i] = null;
                downloadQueue.RemoveAt(i);
            }
        }

        // texture
        public void DownLoadTexture(string url, UnityAction<string, Texture> response)
        {
            DownloadContent downloadContent = downloadQueue.Find(v => v.url == url);
            // 已包含
            if (downloadContent != null)
                downloadContent.response += (u, o) => { response?.Invoke(u, (Texture)o); };
            else
            {
                downloadContent = new DownloadContent();
                downloadContent.url = url;
                downloadContent.response = (u, o) => { response?.Invoke(u, (Texture)o); };
                downloadContent.ie = DownLoadTexIE(downloadContent);
                downloadQueue.Add(downloadContent);
                StartCoroutine(downloadContent.ie);
            }
        }

        private IEnumerator DownLoadTexIE(DownloadContent content)
        {
            content.unityWebRequest = UnityWebRequestTexture.GetTexture(content.url);
            content.unityWebRequest.timeout = timeOut;
            yield return content.unityWebRequest.SendWebRequest();
            if (content.unityWebRequest.isNetworkError || content.unityWebRequest.isHttpError) {
                OnDownloadError(content, DownLoadTexIE(content));
                yield break;
            }
            Log.Info("下载成功：" + content.url);
            DownloadHandlerTexture downloadHandler = content.unityWebRequest.downloadHandler as DownloadHandlerTexture;
            Texture2D tex = downloadHandler.texture;
            if (tex != null)
                tex.name = Path.GetFileName(content.url);
            content.response?.Invoke(content.url, tex);
            StopDownload(content);
        }

        // audio
        public void DownLoadAudio(string url, UnityAction<string, AudioClip> response)
        {
            DownloadContent downloadContent = downloadQueue.Find(v => v.url == url);
            // 已包含
            if (downloadContent != null)
                downloadContent.response += (u, o) => { response?.Invoke(u, (AudioClip)o); };
            else
            {
                downloadContent = new DownloadContent();
                downloadContent.url = url;
                downloadContent.response = (u, o) => { response?.Invoke(u, (AudioClip)o); };
                downloadContent.ie = DownLoadAudioIE(downloadContent);
                downloadQueue.Add(downloadContent);
                StartCoroutine(downloadContent.ie);
            }
        }

        private IEnumerator DownLoadAudioIE(DownloadContent content) {
            content.unityWebRequest = UnityWebRequestMultimedia.GetAudioClip(content.url, AudioType.UNKNOWN);
            content.unityWebRequest.timeout = timeOut;
            yield return content.unityWebRequest.SendWebRequest();
            if (content.unityWebRequest.isNetworkError || content.unityWebRequest.isHttpError) {
                OnDownloadError(content, DownLoadAudioIE(content));
                yield break;
            }
            Log.Info("下载成功：" + content.url);
            DownloadHandlerAudioClip downloadHandler = content.unityWebRequest.downloadHandler as DownloadHandlerAudioClip;
            AudioClip clip = downloadHandler.audioClip;

            // 读取 mp3 无法第一时间获取音频长度，故等待至音频被完全构建
            clip.name = Path.GetFileName(content.url);
            yield return new WaitUntil(() => { return clip.length > 0; });
            content.response?.Invoke(content.url, clip);
            StopDownload(content);
        }

        // assetbundle
        public void DownLoadAssetBundle(string url, UnityAction<string, AssetBundle> response)
        {
            DownloadContent downloadContent = downloadQueue.Find(v => v.url == url);
            // 已包含
            if (downloadContent != null)
                downloadContent.response += (u, o) => { response?.Invoke(u, (AssetBundle)o); };
            else {
                downloadContent = new DownloadContent();
                downloadContent.url = url;
                downloadContent.response = (u, o) => { response?.Invoke(u, (AssetBundle)o); };
                downloadContent.ie = DownLoadAssetBundleIE(downloadContent);
                downloadQueue.Add(downloadContent);
                StartCoroutine(downloadContent.ie);
            }
        }

        private IEnumerator DownLoadAssetBundleIE(DownloadContent content)
        {
            content.url = "file://" + content.url;
            content.unityWebRequest = UnityWebRequestAssetBundle.GetAssetBundle(content.url);
            content.unityWebRequest.timeout = timeOut;
            yield return content.unityWebRequest.SendWebRequest();
            if (content.unityWebRequest.isNetworkError || content.unityWebRequest.isHttpError) {
                OnDownloadError(content, DownLoadAssetBundleIE(content));
                yield break;
            }
            Log.Info("下载成功：" + content.url);
            DownloadHandlerAssetBundle downloadHandler = content.unityWebRequest.downloadHandler as DownloadHandlerAssetBundle;
            AssetBundle assetBundle = downloadHandler.assetBundle;
            if (assetBundle != null)
                assetBundle.name = Path.GetFileName(content.url);
            content.response?.Invoke(content.url, assetBundle);
            StopDownload(content);
        }

        // text
        public void DownloadTextAsset(string url, UnityAction<string, TextAsset> response)
        {
            DownloadContent downloadContent = downloadQueue.Find(v => v.url == url);
            // 已包含
            if (downloadContent != null)
                downloadContent.response += (u, o) => { response?.Invoke(u, (TextAsset)o); };
            else {
                UnityWebRequest unityWebRequest = UnityWebRequest.Get(url);
                unityWebRequest.timeout = timeOut;
                downloadContent = new DownloadContent() { url = url, unityWebRequest = unityWebRequest, response = (u, o) => { response?.Invoke(u, (TextAsset)o); } };
                downloadContent.ie = DownLoadTextAssetIE(downloadContent);
                downloadQueue.Add(downloadContent);
                StartCoroutine(downloadContent.ie);
            }
        }

        private IEnumerator DownLoadTextAssetIE(DownloadContent content)
        {
            content.unityWebRequest = UnityWebRequest.Get(content.url);
            content.unityWebRequest.timeout = timeOut;
            yield return content.unityWebRequest.SendWebRequest();
            if (content.unityWebRequest.isNetworkError || content.unityWebRequest.isHttpError) {
                OnDownloadError(content, DownLoadTextAssetIE(content));
                yield break;
            }
            Log.Info("下载成功：" + content.url);
            DownloadHandler downloadHandler = content.unityWebRequest.downloadHandler;
            TextAsset textAsset = new TextAsset(downloadHandler.text);
            textAsset.name = Path.GetFileName(content.url);
            content.response?.Invoke(content.url, textAsset);
            StopDownload(content);
        }

        // stream
        public void DownloadStream(string url, UnityAction<string, byte[]> response)
        {
            DownloadContent downloadContent = downloadQueue.Find(v => v.url == url);
            // 已包含
            if (downloadContent != null)
                downloadContent.response += (u, o) => { response?.Invoke(u, (byte[])o); };
            else {
                downloadContent = new DownloadContent();
                downloadContent.url = url;
                downloadContent.response = (u, o) => { response?.Invoke(u, (byte[])o); };
                downloadContent.ie = DownLoadStreamIE(downloadContent);
                downloadQueue.Add(downloadContent);
                StartCoroutine(downloadContent.ie);
                
            }
        }
       
        private IEnumerator DownLoadStreamIE(DownloadContent content)
        {
            content.unityWebRequest = UnityWebRequest.Get(content.url);
            content.unityWebRequest.timeout = timeOut;
            yield return content.unityWebRequest.SendWebRequest();
            if (content.unityWebRequest.isNetworkError || content.unityWebRequest.isHttpError) {
                OnDownloadError(content, DownLoadStreamIE(content));
                yield break;
            }
            Log.Info("下载成功：" + content.url);
            DownloadHandler downloadHandler = content.unityWebRequest.downloadHandler;
            content.response?.Invoke(content.url, downloadHandler.data);
            StopDownload(content);
           
        }
        private void StartDownLoadStream()
        {
            if (downloadQueue.Count == 0) return;
            StartCoroutine(DownloadQueue.Dequeue().ie);
        }
        public Queue<DownloadContent> DownloadQueue { get; private set; }


        private void OnDownloadError(DownloadContent content,IEnumerator ie) {
            Log.Info("下载失败：" + content.url + ">>" + content.unityWebRequest.error);
            content.errorCount++;
            if (content.errorCount >= retryCount) {
                content.response?.Invoke(content.url, null);
                StopDownload(content);
            }
            else {
                content.ie = ie;
                StartCoroutine(content.ie);
            }
        }

        #endregion

        public class DownloadContent
        {
            public string url;
            public IEnumerator ie;
            public UnityWebRequest unityWebRequest;
            public UnityAction<string, object> response;
            public int errorCount;                              // 重试次数

            public void Abort()
            {
                if (unityWebRequest != null)
                    unityWebRequest.Abort();
                response = null;
            }
        }
    }
}